Skip to content

Foreground server logo, chat stream trust, and hub edit/scroll polish - #280

Merged
steve02081504 merged 21 commits into
masterfrom
fix
Aug 6, 2026
Merged

Foreground server logo, chat stream trust, and hub edit/scroll polish#280
steve02081504 merged 21 commits into
masterfrom
fix

Conversation

@steve02081504

@steve02081504 steve02081504 commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Foreground server on a real TTY (needs_output) runs the same icon_anime intro/dismiss/farewell session as fount log; path CLI renames run_server_with_updates to run_with_updates and adds a run_server entry for debug + keepalive.
  • Chat Hub stream preview elevates Markdown inline HTML only via strict isTrustedMarkdownAuthor (not blanket !isRemote); reasoning blocks render as Markdown <details> with CommonMark blank lines; add scrollToBottomIfPinned and same-channel hash-nav short-circuit.
  • Consolidate message edit templates into one edit_body, reject empty edits with i18n toast, and cover reasoning Markdown with a pure test.

Test plan

  • Real TTY: fount server shows icon intro, dismisses after start, farewell on shutdown / Ctrl+C mid-intro
  • Non-TTY / background: no logo session
  • Hub: trusted local stream shows reasoning <details>; untrusted/federated stream stays safe preview
  • Hub: while scrolled up, stream/append does not yank to bottom; pinned stays pinned
  • Same group+channel hash with eventId scrolls/highlights without full remount
  • Edit message: empty save shows toast; normal save works
  • fount test --no-parallel shells/chat:pure:reasoning_markdown

摘要

  • 前台服务器统一复用 icon_anime 会话,并拆分 run_serverrun_with_updates
  • Chat Hub 收紧 Markdown 与主动 HTML 的信任边界,支持可信 reasoning <details> 渲染、贴底滚动和重复导航抑制。
  • 消息编辑统一使用 edit_body,增加快捷键提示、空内容校验和国际化文案。
  • 将正常中断退出码改为 0,并更新虚拟控制台依赖。
  • 新增仓库描述自动化流程,支持按日期、节日和多语言描述更新仓库信息。

原因

统一前台服务器与 TTY 动画行为。
降低流式渲染、内联 HTML、事件属性和危险 URL 的风险。
减少消息编辑模板重复,改善编辑体验和可访问性。
自动维护仓库描述,减少人工操作。

架构与审美风险

  • StreamRenderer 的异步信任切换同时触发缓存清理和 DOM 重渲染,时序复杂。
  • reasoning 将原始 <details> 交给 Markdown 管线,输出依赖下游的 HTML 和空行处理。
  • run_server 集中调试参数、前台启动和 keepalive 入口,职责更清晰,但入口层更集中。
  • 编辑模板重组并移除旧接口,结构更干净,但调用方必须统一使用 editBodyHtml
  • 仓库描述自动化引入日期、节日匹配和外部依赖,配置与工作流耦合度上升。

@cursor

cursor Bot commented Aug 6, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

本次变更更新服务器图标生命周期、路径 CLI、日志退出码、消息编辑器、滚动导航、流式信任渲染、HTML 清理、本地化结构、推理 Markdown 渲染和仓库描述自动更新。

Changes

服务器与路径运行时

Layer / File(s) Summary
服务器图标与正常退出
deno.json, imgs/icon_anime/*, src/server/index.mjs, src/log_viewer/*
服务器启动和关闭时使用图标会话。播放器阻塞虚拟控制台输出,并直接写入目标流。日志查看器的中止和主循环退出码改为 0
路径服务器入口与更新重启
AGENTS.md, path/src/run.*, path/src/cmd/*
新增 run_server,统一处理 debug 参数。run_with_updates 保留更新和退出码 131 的重启流程。

聊天界面与内容渲染

Layer / File(s) Summary
消息编辑结构与提交流程
src/decl/locale_data.ts, src/public/locales/*, src/public/parts/shells/chat/public/src/templates/hub/messages/*, src/public/parts/shells/chat/public/hub/messages/*, src/public/parts/shells/chat/public/hub/widgets.css
编辑本地化字段改为结构化对象。编辑界面统一使用新模板。保存流程拒绝空白文本,并增加编辑器布局和提示样式。
滚动、导航与流式信任
src/public/parts/shells/chat/public/src/MessagePipeline.mjs, src/public/parts/shells/chat/public/hub/*, src/public/parts/shells/chat/public/src/ui/StreamRenderer.mjs
新增贴底滚动 API。流式内容按作者身份更新信任档。流式更新仅在视图已贴底时滚动。
HTML 清理与翻译处理
src/public/pages/scripts/lib/sanitizeHtml.mjs, src/public/pages/scripts/i18n/index.mjs, src/public/parts/shells/chat/test/pure/sanitize_display_html.test.mjs, src/public/pages/AGENTS.md
新增字符串和 DOM 输入的主动内容清理。清理事件属性、危险 URL 和 srcset。复合翻译键不再清空已有文本。
推理详情 Markdown 渲染
src/public/parts/serviceGenerators/AI/*, src/public/parts/serviceGenerators/AI/proxy/src/reasoningRenderer.mjs, src/public/parts/shells/chat/test/pure/reasoning_markdown.test.mjs
推理正文和摘要改由 buildReasoningDetailsMarkdown 合并。测试覆盖代码围栏、空行、摘要连接和空数据。

仓库描述自动更新

Layer / File(s) Summary
描述选择与 GitHub Action
.github/actions/update-repo-description/*, .github/repo-descriptions.json, .github/workflows/update_repo_description.yaml
新增描述选择脚本、复合 Action、节日描述配置和定时工作流。工作流支持文件变更、定时及手动日期触发。

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
审美与简洁 ⚠️ Warning 未通过:pick.py:76-80 保留旧 descriptions 兼容分支;sanitizeHtml.mjs:115 重复声明 DocumentFragment;编辑模板新增空 spacer,且 mt-1.5 与 .message-edit-hint 的 margin:0 冲突。 直接读取 extras,删除旧字段和类型分支;去重返回类型;用 margin-left:auto 替代 spacer,并删除冲突的 hint 样式或工具类。
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了前台服务器图标、聊天流信任控制以及 Hub 编辑和滚动优化等主要变更。
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

codacy-production Bot commented Aug 6, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 71 complexity · 0 duplication

Metric Results
Complexity 71
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@path/src/cmd/keepalive.ps1`:
- Line 31: 移除两个 keepalive 入口中的重复 debug 解析逻辑:在 path/src/cmd/keepalive.ps1 的 31-31
行对应入口中删除本地 debug_on 及参数剥离分支,直接将 $commandArguments 传给 run_server;在
path/src/cmd/keepalive.sh 的 18-18 行对应入口中删除本地 debug_on 及 shift 分支,直接将 "$@" 传给
run_server,使 debug 解析统一由 run_server 负责。

In `@src/public/locales/ar-SA.json`:
- Around line 2312-2315: Update both the title and aria-label values in the
upload translation object to use “رفع” instead of “تحميل المرفق”, matching the
existing upload wording in the locale file.

In `@src/public/locales/de-DE.json`:
- Line 2316: 统一 de-DE.json 中快捷键提示的按键名称:将该处的 “Strg+Enter” 与同语言环境另一处使用的
“Strg+Eingabe” 保持一致,并保留其余提示文案不变。

In `@src/public/locales/fr-FR.json`:
- Line 2316: Update the hint translation in the locale entry to use the
correctly accented “Échap” spelling and add “pour” so the shortcut actions are
expressed clearly, while preserving the existing Ctrl+Entrée and cancel
semantics.

In `@src/public/parts/serviceGenerators/AI/proxy/src/reasoningRenderer.mjs`:
- Line 29: Update the escaping-behavior documentation near the reasoning
renderer to state that reasoning_summary and the正文 are both emitted unchanged,
including preserving markup such as <gamma>; remove the inaccurate claim that
only the summary text is HTML-escaped, while leaving the rendering
implementation unchanged.

In `@src/public/parts/shells/chat/public/hub/hashNav.mjs`:
- Line 46: Remove the unnecessary !channelId fallback from the sameChannel
comparison in src/public/parts/shells/chat/public/hub/hashNav.mjs:46-46,
comparing channelId directly with store.context.currentChannelId. Apply the same
direct comparison in
src/public/parts/shells/chat/public/hub/wiring/bootstrap.mjs:77-77.

In `@src/public/parts/shells/chat/public/src/ui/StreamRenderer.mjs`:
- Around line 111-113: 修正 StreamRenderer 的 HTML 写入逻辑,不要将 innerHTML 视为完整脚本隔离边界:在
src/public/parts/shells/chat/public/src/ui/StreamRenderer.mjs:111-113 的
renderMarkdownAsString/#allowDangerousHtml 路径中仅写入安全档,或为可信档接入完整的事件属性、SVG 事件及
javascript: URL 清洗;同步更新该文件 :3-10 的文件头和构造函数注释,以及
src/public/parts/shells/chat/public/hub/AGENTS.md:16 的相关安全说明。

In `@src/public/parts/shells/chat/test/pure/reasoning_markdown.test.mjs`:
- Line 10: Rename the test variable md to markdown at
src/public/parts/shells/chat/test/pure/reasoning_markdown.test.mjs lines 10-10,
25-25, and 44-44, updating all references at each site accordingly.
- Line 16: Update both CSS class assertions in reasoning_markdown.test.mjs at
lines 16-16 and 30-30 to expect bg-base-200/30 instead of bg-base-200/60,
matching the renderer output.

In `@src/server/index.mjs`:
- Around line 152-154: 在 showIcon 分支中仅当 result === 'started' 时调用
icon.dismiss();result === 'already_running' 时保留已注册的 on_shutdown 路径,由其调用
icon.farewell(),不要取消进行中的 intro。
- Line 141: 在计算 showIcon 前先调用 server.mjs 的 init(),确保缺失的 starts 对象及 starts.Base
已按默认值补齐;然后复用 init() 产生的配置计算图标状态,使缺失 Base 时保持 true,并避免直接访问未定义的 starts。
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 690ae2fd-d141-46e7-a105-2cb7d740c76a

📥 Commits

Reviewing files that changed from the base of the PR and between 1bffb10 and 8fa8839.

📒 Files selected for processing (55)
  • AGENTS.md
  • deno.json
  • imgs/icon_anime/AGENTS.md
  • imgs/icon_anime/player.mjs
  • imgs/icon_anime/session.mjs
  • path/src/cmd/keepalive.ps1
  • path/src/cmd/keepalive.sh
  • path/src/cmd/server.ps1
  • path/src/cmd/server.sh
  • path/src/run.ps1
  • path/src/run.sh
  • src/decl/locale_data.ts
  • src/log_viewer/index.mjs
  • src/log_viewer/interactive.mjs
  • src/public/locales/ar-SA.json
  • src/public/locales/de-DE.json
  • src/public/locales/emoji.json
  • src/public/locales/en-UK.json
  • src/public/locales/es-ES.json
  • src/public/locales/fr-FR.json
  • src/public/locales/hi-IN.json
  • src/public/locales/is-IS.json
  • src/public/locales/it-IT.json
  • src/public/locales/ja-JP.json
  • src/public/locales/ko-KR.json
  • src/public/locales/lzh.json
  • src/public/locales/nl-NL.json
  • src/public/locales/pt-PT.json
  • src/public/locales/ru-RU.json
  • src/public/locales/uk-UA.json
  • src/public/locales/vi-VN.json
  • src/public/locales/zh-CN.json
  • src/public/locales/zh-TW.json
  • src/public/pages/scripts/i18n/index.mjs
  • src/public/parts/serviceGenerators/AI/atlascloud/main.mjs
  • src/public/parts/serviceGenerators/AI/evolink/main.mjs
  • src/public/parts/serviceGenerators/AI/proxy/main.mjs
  • src/public/parts/serviceGenerators/AI/proxy/src/reasoningRenderer.mjs
  • src/public/parts/shells/chat/public/hub/AGENTS.md
  • src/public/parts/shells/chat/public/hub/hashNav.mjs
  • src/public/parts/shells/chat/public/hub/messages/actions/edit.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageActionsUi.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageScroll.mjs
  • src/public/parts/shells/chat/public/hub/stream/volatileSlots.mjs
  • src/public/parts/shells/chat/public/hub/widgets.css
  • src/public/parts/shells/chat/public/hub/wiring/bootstrap.mjs
  • src/public/parts/shells/chat/public/src/MessagePipeline.mjs
  • src/public/parts/shells/chat/public/src/templates/hub/messages/edit_area.html
  • src/public/parts/shells/chat/public/src/templates/hub/messages/edit_body.html
  • src/public/parts/shells/chat/public/src/templates/hub/messages/edit_channel_body.html
  • src/public/parts/shells/chat/public/src/templates/hub/messages/edit_user_body.html
  • src/public/parts/shells/chat/public/src/ui/StreamRenderer.mjs
  • src/public/parts/shells/chat/src/streaming/toolBlocks.mjs
  • src/public/parts/shells/chat/test/pure/reasoning_markdown.test.mjs
  • src/server/index.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)
💤 Files with no reviewable changes (3)
  • src/public/parts/shells/chat/public/src/templates/hub/messages/edit_user_body.html
  • src/public/parts/shells/chat/public/src/templates/hub/messages/edit_area.html
  • src/public/parts/shells/chat/public/src/templates/hub/messages/edit_channel_body.html

Comment thread path/src/cmd/keepalive.ps1
Comment thread src/public/locales/ar-SA.json
Comment thread src/public/locales/de-DE.json Outdated
Comment thread src/public/locales/fr-FR.json Outdated
Comment thread src/public/parts/serviceGenerators/AI/proxy/src/reasoningRenderer.mjs Outdated
Comment thread src/public/parts/shells/chat/public/src/ui/StreamRenderer.mjs Outdated
Comment thread src/public/parts/shells/chat/test/pure/reasoning_markdown.test.mjs Outdated
Comment thread src/public/parts/shells/chat/test/pure/reasoning_markdown.test.mjs Outdated
Comment thread src/server/index.mjs
}
}

const showIcon = Boolean(fount_config.needs_output && fount_config.starts.Base)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

先对齐 init() 的默认值,再计算 showIcon

Line 141 在调用 init() 前直接读取 fount_config.starts.Base。当配置省略 starts 时,服务器会先抛出 TypeError。当 starts 存在但没有 Base 时,图标也会错误地被关闭。

init() 已将缺失的 starts.Base 默认设为 true。这里必须复用同一语义。

建议修正
-const showIcon = Boolean(fount_config.needs_output && fount_config.starts.Base)
+const showIcon = Boolean(fount_config.needs_output && (fount_config.starts?.Base ?? true))

根据提供的上游合约,src/server/server.mjs:init() 会在缺失 starts 时补齐对象,并将 Base 默认设为 true

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const showIcon = Boolean(fount_config.needs_output && fount_config.starts.Base)
const showIcon = Boolean(fount_config.needs_output && (fount_config.starts?.Base ?? true))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/index.mjs` at line 141, 在计算 showIcon 前先调用 server.mjs 的
init(),确保缺失的 starts 对象及 starts.Base 已按默认值补齐;然后复用 init() 产生的配置计算图标状态,使缺失 Base 时保持
true,并避免直接访问未定义的 starts。

Comment thread src/server/index.mjs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/public/parts/serviceGenerators/AI/proxy/src/reasoningRenderer.mjs (1)

42-58: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

将推理正文转为 Markdown 再插入详情容器。

reasoningContentreasoningSummary 仍带原始 Markdown,例如代码围栏在渲染后会原样保留而不是变成代码块;reasoningRenderer.mjs/测试中应覆盖带围栏的渲染结果,或先渲染正文再拼回 <div class="collapse-content">

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/public/parts/serviceGenerators/AI/proxy/src/reasoningRenderer.mjs` around
lines 42 - 58, Update the rendering flow around the reasoningContent body
assembly and the collapse-content output so the combined reasoning text is
converted from Markdown to HTML before insertion, preserving fenced code blocks
as rendered code blocks. Use the existing Markdown renderer, and add or update
reasoningRenderer.mjs tests to cover fenced-code rendering within the details
container.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/public/pages/scripts/lib/sanitizeHtml.mjs`:
- Around line 79-80: Update collectDescendants() and the traversal used by
scrubHtmlActivePayload(root) and sanitizeHtmlTree(root) in
src/public/pages/scripts/lib/sanitizeHtml.mjs:79-80,116-119 to process root
itself before or while traversing all descendants through the same
attribute-sanitization flow. Add coverage in
src/public/parts/shells/chat/test/pure/sanitize_display_html.test.mjs:63-68 by
placing an onclick or dangerous URL on the host root and asserting the attribute
is removed after sanitization.

---

Outside diff comments:
In `@src/public/parts/serviceGenerators/AI/proxy/src/reasoningRenderer.mjs`:
- Around line 42-58: Update the rendering flow around the reasoningContent body
assembly and the collapse-content output so the combined reasoning text is
converted from Markdown to HTML before insertion, preserving fenced code blocks
as rendered code blocks. Use the existing Markdown renderer, and add or update
reasoningRenderer.mjs tests to cover fenced-code rendering within the details
container.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 12889486-3596-49b3-9db3-6b442503f743

📥 Commits

Reviewing files that changed from the base of the PR and between 8fa8839 and ca02082.

📒 Files selected for processing (15)
  • path/src/cmd/keepalive.ps1
  • path/src/cmd/keepalive.sh
  • src/public/locales/ar-SA.json
  • src/public/locales/de-DE.json
  • src/public/locales/fr-FR.json
  • src/public/pages/AGENTS.md
  • src/public/pages/scripts/lib/sanitizeHtml.mjs
  • src/public/parts/serviceGenerators/AI/proxy/src/reasoningRenderer.mjs
  • src/public/parts/shells/chat/public/hub/AGENTS.md
  • src/public/parts/shells/chat/public/hub/hashNav.mjs
  • src/public/parts/shells/chat/public/hub/wiring/bootstrap.mjs
  • src/public/parts/shells/chat/public/src/ui/StreamRenderer.mjs
  • src/public/parts/shells/chat/test/pure/reasoning_markdown.test.mjs
  • src/public/parts/shells/chat/test/pure/sanitize_display_html.test.mjs
  • src/server/index.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)
💤 Files with no reviewable changes (1)
  • path/src/cmd/keepalive.sh

Comment thread src/public/pages/scripts/lib/sanitizeHtml.mjs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/public/pages/scripts/lib/sanitizeHtml.mjs`:
- Around line 79-80: 在 collectDescendants() 的非元素根节点分支中,移除对 root.childNodes
的展开数组分配,直接使用 root.childNodes 进行只读遍历;保留元素节点分支及现有 walk(child) 处理逻辑不变。
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5985a2d9-b527-4fa4-bdb5-f31525dbecd3

📥 Commits

Reviewing files that changed from the base of the PR and between ca02082 and a05baaa.

📒 Files selected for processing (2)
  • src/public/pages/scripts/lib/sanitizeHtml.mjs
  • src/public/parts/shells/chat/test/pure/sanitize_display_html.test.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)

Comment thread src/public/pages/scripts/lib/sanitizeHtml.mjs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/public/pages/scripts/lib/sanitizeHtml.mjs (2)

127-136: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

在不可信 HTML 路径中移除 style 属性。

Line 127-136 只移除危险标签和活动属性。它不会清除 style 中的 CSS。

sanitizePermissiveHtml() 会处理 displayNamesubtitle,随后由 src/public/parts/shells/chat/public/hub/mentionAutocomplete.mjs:64-94 写入 innerHTML。攻击者可以注入定位样式覆盖控件,也可以通过 CSS url(...) 发起外部请求。

请在 sanitizeHtmlTree() 的不可信路径中删除 style,或只允许严格的 CSS 属性和值。不要把该规则无条件应用到允许可信 Markdown 的 scrubHtmlActivePayload()

建议修改
-		if (BLOCKED_HTML_TAGS.has(tagName))
+		if (BLOCKED_HTML_TAGS.has(tagName)) {
 			el.remove()
+			continue
+		}
+		el.removeAttribute('style')

As per path instructions: 对富文本或用户控制内容使用共享清洗工具,并拒绝危险 URL scheme;不可信 CSS 内容也必须纳入清洗范围。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/public/pages/scripts/lib/sanitizeHtml.mjs` around lines 127 - 136, Update
sanitizeHtmlTree to remove or strictly sanitize style attributes on every
element in the untrusted HTML path, including CSS values that can trigger
external requests or positioning attacks. Keep scrubHtmlActivePayload’s trusted
Markdown behavior unchanged and continue using the shared sanitization flow.

Source: Path instructions


92-105: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

使用完整变量名替代 elattr

Line 92-105 使用缩写。安全清洗代码应直接使用 elementattribute,避免审计时产生歧义。

建议修改
-		const el = /** `@type` {Element} */ (node)
-		for (const attr of [...el.attributes]) {
-			const lowerName = attr.name.toLowerCase()
+		const element = /** `@type` {Element} */ (node)
+		for (const attribute of [...element.attributes]) {
+			const lowerName = attribute.name.toLowerCase()
 			if (lowerName.startsWith('on')) {
-				el.removeAttribute(attr.name)
+				element.removeAttribute(attribute.name)
 				continue
 			}
 			if (!URL_HTML_ATTRIBUTES.has(lowerName)) continue
 			if (lowerName === 'srcset') {
-				el.removeAttribute(attr.name)
+				element.removeAttribute(attribute.name)
 				continue
 			}
-			if (!isSafeHtmlUrl(attr.value))
-				el.removeAttribute(attr.name)
+			if (!isSafeHtmlUrl(attribute.value))
+				element.removeAttribute(attribute.name)

As per path instructions: 命名应使用可读的完整词,不使用难以理解的缩写。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/public/pages/scripts/lib/sanitizeHtml.mjs` around lines 92 - 105,
在节点属性清洗逻辑中,将变量名 el 和 attr 分别重命名为 element 和 attribute,并同步更新该循环内所有引用;保持现有
sanitizeHtml 清洗行为不变。

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/public/pages/scripts/lib/sanitizeHtml.mjs`:
- Around line 127-136: Update sanitizeHtmlTree to remove or strictly sanitize
style attributes on every element in the untrusted HTML path, including CSS
values that can trigger external requests or positioning attacks. Keep
scrubHtmlActivePayload’s trusted Markdown behavior unchanged and continue using
the shared sanitization flow.
- Around line 92-105: 在节点属性清洗逻辑中,将变量名 el 和 attr 分别重命名为 element 和
attribute,并同步更新该循环内所有引用;保持现有 sanitizeHtml 清洗行为不变。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 44f5adac-ada1-425e-9e14-9d9830e9c4b0

📥 Commits

Reviewing files that changed from the base of the PR and between a05baaa and 0de921d.

📒 Files selected for processing (1)
  • src/public/pages/scripts/lib/sanitizeHtml.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)

Comment on lines +21 to +38
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Update description
id: update
uses: ./.github/actions/update-repo-description
with:
token: ${{ secrets.GH_TOKEN }}
date: ${{ github.event.inputs.date || '' }}
- name: Summary
run: |
{
echo "### Repo description updated"
echo ""
echo "- **date:** \`${{ steps.update.outputs.date }}\`"
echo "- **holiday:** \`${{ steps.update.outputs.holiday || '(none)' }}\`"
echo "- **description:** ${{ steps.update.outputs.description }}"
} >> "$GITHUB_STEP_SUMMARY"

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/public/pages/scripts/lib/sanitizeHtml.mjs (1)

110-115: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

统一 HTML 清理契约。

实现会在 Line 100-102 无条件删除 srcset,并在 Line 136 删除 style。当前两处 JSDoc 和 AGENTS.md 的说明不完整。

  • src/public/pages/scripts/lib/sanitizeHtml.mjs#L110-L115: 明确移除 on*、所有 srcset 和不安全 URL,并保留 style
  • src/public/pages/scripts/lib/sanitizeHtml.mjs#L1-L4: 补充 sanitizePermissiveHtml 会移除 style
  • src/public/pages/AGENTS.md#L41-L41: 同步说明 srcset 会无条件移除。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/public/pages/scripts/lib/sanitizeHtml.mjs` around lines 110 - 115,
统一更新清理契约文档:在 src/public/pages/scripts/lib/sanitizeHtml.mjs 第110-115行的 JSDoc
中明确移除 on* 属性、所有 srcset 和不安全 URL,并保留 style;在同文件第1-4行补充 sanitizePermissiveHtml 会移除
style;在 src/public/pages/AGENTS.md 第41行同步说明 srcset 会被无条件移除。
src/public/parts/shells/chat/test/pure/sanitize_display_html.test.mjs (1)

75-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

内联只使用一次的 returned

returned 只用于下一行比较。直接内联调用,减少无意义绑定。

建议修改
-	const returned = scrubHtmlActivePayload(host)
-	assertEquals(returned, host)
+	assertEquals(scrubHtmlActivePayload(host), host)

As per path instructions,禁止只用一次的临时绑定,应直接内联到使用处。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/public/parts/shells/chat/test/pure/sanitize_display_html.test.mjs` around
lines 75 - 76, 在 sanitize_display_html 测试中移除仅使用一次的 returned 变量,直接将
scrubHtmlActivePayload(host) 的调用内联到后续 assertEquals 比较中,保持断言对象与现有行为不变。

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/actions/update-repo-description/pick.py:
- Line 100: Replace the abbreviated identifiers in the relevant file-handling
and argument-parsing code: rename the output file handle from f to output_file,
the configuration file handle from f to config_file, and argv to arguments.
Update all references consistently while preserving the existing behavior.
- Around line 28-40: Rename lunar_md to lunar_month_day and jieqi_name to
solar_term_name, updating every reference to these functions so their names
clearly express the returned domain values. Preserve their existing behavior and
signatures.
- Around line 76-80: 删除配置读取中的旧 descriptions 回退:在 extras 不是列表时不要再读取
config.get('descriptions'),仅基于当前 extras 配置处理并保留列表复制行为;同时确保不添加兼容逻辑、@deprecated
标记或重导出。
- Around line 43-61: 在 holiday_matches 中内联只使用一次的 md 和 iso,直接使用
today.strftime('%m-%d') 与 today.isoformat();将生成器变量 d、lmd、jq 分别重命名为
date_value、lunar_date、solar_term。移除 yearday 的条件分支和末尾冗余 return,直接返回年内日比较结果。

In @.github/repo-descriptions.json:
- Around line 2-13: 删除配置中的 slogan 字段及其对应的品牌层级注释,保持 core、extras 和节日匹配键的现有配置不变;无需在
pick.py 中增加消费者或替代逻辑。

In @.github/workflows/update_repo_description.yaml:
- Around line 19-28: Update the update description workflow to tighten access
and prevent credential leakage: in
.github/workflows/update_repo_description.yaml, add a job-level permissions
block with contents: read and change the actions/checkout@v6 step to use a fixed
commit SHA with persist-credentials set to false; in
.github/actions/update-repo-description/action.yaml, replace any installation
flow that resolves latest/tagged package versions with locked dependency-file
based installs for json5 and sxtwl so the action does not parse or fetch mutable
tags.

In `@src/public/pages/scripts/lib/sanitizeHtml.mjs`:
- Around line 99-105: 更新 isSafeHtmlUrl(),将以“//”或“/\”开头的协议相对 URL
都判定为不安全,保留其他现有校验行为;并为反斜杠开头的协议相对 URL 补充回归测试,覆盖其在危险 URL 属性中会被移除。

---

Outside diff comments:
In `@src/public/pages/scripts/lib/sanitizeHtml.mjs`:
- Around line 110-115: 统一更新清理契约文档:在
src/public/pages/scripts/lib/sanitizeHtml.mjs 第110-115行的 JSDoc 中明确移除 on* 属性、所有
srcset 和不安全 URL,并保留 style;在同文件第1-4行补充 sanitizePermissiveHtml 会移除 style;在
src/public/pages/AGENTS.md 第41行同步说明 srcset 会被无条件移除。

In `@src/public/parts/shells/chat/test/pure/sanitize_display_html.test.mjs`:
- Around line 75-76: 在 sanitize_display_html 测试中移除仅使用一次的 returned 变量,直接将
scrubHtmlActivePayload(host) 的调用内联到后续 assertEquals 比较中,保持断言对象与现有行为不变。
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8ffd9530-4c1f-4c12-9bf3-6eea4a0e2a00

📥 Commits

Reviewing files that changed from the base of the PR and between 0de921d and cff5ad5.

📒 Files selected for processing (7)
  • .github/actions/update-repo-description/action.yaml
  • .github/actions/update-repo-description/pick.py
  • .github/repo-descriptions.json
  • .github/workflows/update_repo_description.yaml
  • src/public/pages/AGENTS.md
  • src/public/pages/scripts/lib/sanitizeHtml.mjs
  • src/public/parts/shells/chat/test/pure/sanitize_display_html.test.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)

Comment thread .github/actions/update-repo-description/pick.py Outdated
Comment thread .github/actions/update-repo-description/pick.py Outdated
Comment on lines +76 to +80
extras = config.get('extras')
if not isinstance(extras, list):
extras = list(config.get('descriptions') or ())
else:
extras = list(extras)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

删除旧 descriptions 配置回退。

当前配置定义 extrasdescriptions 回退继续维护未声明的旧格式,并增加配置语义分支。

建议修改
-	extras = config.get('extras')
-	if not isinstance(extras, list):
-		extras = list(config.get('descriptions') or ())
-	else:
-		extras = list(extras)
+	extras = list(config.get('extras') or ())

As per path instructions: “不向后兼容;不做 @deprecated / 重导出;删就删干净。”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
extras = config.get('extras')
if not isinstance(extras, list):
extras = list(config.get('descriptions') or ())
else:
extras = list(extras)
extras = list(config.get('extras') or ())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/update-repo-description/pick.py around lines 76 - 80,
删除配置读取中的旧 descriptions 回退:在 extras 不是列表时不要再读取 config.get('descriptions'),仅基于当前
extras 配置处理并保留列表复制行为;同时确保不添加兼容逻辑、@deprecated 标记或重导出。

Source: Path instructions

Comment thread .github/actions/update-repo-description/pick.py Outdated
Comment thread .github/repo-descriptions.json Outdated
Comment on lines +19 to +28
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Update description
id: update
uses: ./.github/actions/update-repo-description
with:
token: ${{ secrets.GH_TOKEN }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files matching workflow/action:\n'
git ls-files | rg '(^|/)\.github/(workflows|actions)'

printf '\nworkflow excerpt:\n'
if [ -f .github/workflows/update_repo_description.yaml ]; then
  cat -n .github/workflows/update_repo_description.yaml | sed -n '1,80p'
fi
if [ -f .github/workflows/update-repo-description.yaml ]; then
  cat -n .github/workflows/update-repo-description.yaml | sed -n '1,80p'
fi

printf '\naction excerpt:\n'
if [ -f .github/actions/update-repo-description/action.yaml ]; then
  cat -n .github/actions/update-repo-description/action.yaml | sed -n '1,140p'
fi

printf '\nSearch for persist-credentials, permissions, checkout, pip install in repo:\n'
rg -n 'persist-credentials|permissions:|actions/checkout|pip install|json5|sxtwl|requirements|lock' .github || true

Repository: steve02081504/fount

Length of output: 12519


🏁 Script executed (no clone):

#!/bin/bash
set -euo pipefail

printf 'actions/checkout@v6 ref details:\n'
gh api repos/actions/checkout/git/refs/tags/v6 --jq '{ref, object_type:.object.type, object_sha:.object.sha}' || true

TAG_OBJECT_SHA=$(gh api repos/actions/checkout/git/refs/tags/v6 --jq '.object.sha')
TAG_OBJECT_TYPE=$(gh api repos/actions/checkout/git/refs/tags/v6 --jq '.object.type')
if [ "$TAG_OBJECT_TYPE" = "tag" ]; then
  printf '\nAnnotated tag dereference:\n'
  gh api repos/actions/checkout/git/tags/"$TAG_OBJECT_SHA" --jq '{object_type:.object.type, commit_sha:.object.sha, tag:.tag}' || true
fi

printf '\nGitHub checkout action v6 docs relevant inputs:\n'
curl -sSL 'https://raw.githubusercontent.com/actions/checkout/v6/action.yml' | sed -n '1,120p'

Length of output: 5453


移除 checkout 的持久化凭据并限制作业权限。

该 job 执行 actions/checkout@v6 后才运行 action,且没有显式 permissionsactions/checkout 默认把令牌写入 git config。未解析最新版本的 json5 / sxtwl 安装代码有机会读取该凭据。

  • update_repo_description.yaml 中设置 permissions: { contents: read },且 checkout 使用固定 SHA、配置 persist-credentials: false
  • update-repo-description/action.yaml 使用锁定依赖文件安装 json5sxtwl,不要解析临时标签。
🧰 Tools
🪛 zizmor (1.29.0)

[warning] 23-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[info] 20-20: workflow or action definition without a name (anonymous-definition): this job

(anonymous-definition)

📍 Affects 2 files
  • .github/workflows/update_repo_description.yaml#L19-L28 (this comment)
  • .github/actions/update-repo-description/action.yaml#L36-L38
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/update_repo_description.yaml around lines 19 - 28, Update
the update description workflow to tighten access and prevent credential
leakage: in .github/workflows/update_repo_description.yaml, add a job-level
permissions block with contents: read and change the actions/checkout@v6 step to
use a fixed commit SHA with persist-credentials set to false; in
.github/actions/update-repo-description/action.yaml, replace any installation
flow that resolves latest/tagged package versions with locked dependency-file
based installs for json5 and sxtwl so the action does not parse or fetch mutable
tags.

Source: Linters/SAST tools

Comment thread src/public/pages/scripts/lib/sanitizeHtml.mjs
@steve02081504
steve02081504 merged commit 5aed310 into master Aug 6, 2026
32 checks passed
@steve02081504
steve02081504 deleted the fix branch August 6, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants